import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:x3_charts_core/model/dot_line_chart_model.dart';

///**
///* @author hrongyong
///* @date   2/24/21
///* @email hrongyong@gmail.com
///* Description:
///*/
class DotLineChartPainter extends CustomPainter {
  ///图表数组
  final List<DotLineChartModel> chartList;

  ///圆点是否为实心
  final bool dotIsSolid;

  ///第一个折线的点的颜色
  final Color firstPointColor;

  ///第一个折线的点的描述的颜色
  final Color firstDescriptionColor;

  ///第一个折线的颜色
  final Color firstPolylineColor;

  ///第二个折线的点的颜色
  final Color secondPointColor;

  ///第二个折线的点的描述的颜色
  final Color secondDescriptionColor;

  ///第二个折线的颜色
  final Color secondPolylineColor;

  ///Y轴最大值
  final int yAxisMax;

  ///x轴线颜色
  final Color xAxisColor;

  ///x轴线描述颜色
  final Color xAxisDescriptionColor;

  ///y轴线颜色
  final Color yAxisColor;

  ///y轴线描述颜色
  final Color yAxisDescriptionColor;

  ///背景颜色
  final Color backgroundColor;

  ///动画数值
  final Animation<double> repaint;

  DotLineChartPainter({
    @required this.chartList,
    @required this.repaint,
    @required this.yAxisMax,
    this.firstPointColor = const Color(0xFF50C4F7),
    this.firstDescriptionColor = const Color(0xFF50C4F7),
    this.firstPolylineColor = const Color(0xFF50C4F7),
    this.secondPointColor = const Color.fromARGB(255, 200, 58, 104),
    this.secondDescriptionColor = const Color.fromARGB(255, 200, 58, 104),
    this.secondPolylineColor = const Color.fromARGB(255, 200, 58, 104),
    this.xAxisColor = Colors.black12,
    this.yAxisColor = Colors.black12,
    this.xAxisDescriptionColor = Colors.black,
    this.yAxisDescriptionColor = Colors.black,
    this.backgroundColor = Colors.white,
    this.dotIsSolid,
  }) : super(repaint: repaint);

  double maxWidth = 0.0;
  double maxHeight = 0.0;
  double xStep = 0.0; // x 间隔
  double yStep = 0.0; // y 间隔

  ///左边间距
  double leftMargin = 0.0;

  ///底部间距
  double bottomMargin = 0.0;

  ///间距
  EdgeInsets chartPadding;

  ///轴线画笔
  Paint axisPaint = Paint()..strokeWidth = 1.0;

  ///文字
  final TextPainter _textPainter = TextPainter(textDirection: TextDirection.ltr);

  final List<Offset> firstPolyLineOffset = []; // 折线点位信息
  final List<Offset> secondPolylineOffset = []; // 折线点位信息
  //折线
  Paint linePaint = Paint()
    ..color = Colors.red
    ..strokeCap = StrokeCap.round
    ..strokeJoin = StrokeJoin.round
    ..style = PaintingStyle.stroke;

  @override
  void paint(Canvas canvas, Size size) {
    if (chartList.length == 0) return;

    ///确定左边和下边的距离
    TextPainter painter = TextPainter(
        maxLines: 1,
        textDirection: TextDirection.ltr,
        text: TextSpan(
            text: yAxisMax.toString(),
            style: TextStyle(
              fontSize: 10,
            )));
    painter.layout();
    leftMargin = painter.width;
    bottomMargin = painter.height;

    ///确定左边间距
    chartPadding = EdgeInsets.only(left: leftMargin + 2, bottom: bottomMargin + 4, right: 10, top: 10);

    ///可绘画的宽度
    maxWidth = size.width - chartPadding.left - chartPadding.right;

    /// x 间隔
    xStep = maxWidth / (chartList.length - 1);

    ///可绘画的高度
    maxHeight = size.height - chartPadding.top - chartPadding.bottom;

    /// y 间隔
    yStep = maxHeight / 10;

    ///绘制背景
    canvas.drawRect(Offset.zero & size, Paint()..color = backgroundColor);

    ///移动绘画中心
    canvas.translate(chartPadding.left, size.height - chartPadding.bottom);

    ///绘制X轴刻度和文本
    drawXAxisScaleAndText(canvas, size);

    ///绘制Y轴刻度和文本
    drawYAxisScaleAndText(canvas, size);

    ///收集点的位置
    locationOfCollectionPoint(canvas, size);

    ///绘制第一根折线
    //是否要绘制第一根折线
    double firstValue = 0.0;
    firstPolyLineOffset.forEach((element) {
      firstValue = (element.dy == 0.0 || element.dy == -1) ? firstValue : element.dy;
    });
    if (firstValue != 0.0) drawLineChart(canvas: canvas, line: firstPolyLineOffset, lineColor: firstPolylineColor);

    ///绘制第二根折线
    //是否要绘制第二根折线
    double secondValue = 0;
    secondPolylineOffset.forEach((element) {
      secondValue = (element.dy == 0.0 || element.dy == -1) ? secondValue : element.dy;
    });
    if (secondValue != 0.0) drawLineChart(canvas: canvas, line: secondPolylineOffset, lineColor: secondPolylineColor);

    ///绘制第一根折线的点
    if (firstValue != 0.0) drawDots(canvas: canvas, line: firstPolyLineOffset, drawColor: firstPointColor);
    drawDescriptionText(canvas, size, firstPolyLineOffset, firstDescriptionColor, isDraw: firstValue != 0.0);

    ///绘制第一根折线的点的描述文本
    ///绘制第二根折线的点
    if (secondValue != 0.0) drawDots(canvas: canvas, line: secondPolylineOffset, drawColor: secondPointColor);

    ///绘制第二根折线的点的描述文本
    drawDescriptionText(canvas, size, secondPolylineOffset, secondDescriptionColor, isDraw: secondValue != 0.0, isFirst: false);
  }

  drawDescriptionText(Canvas canvas, Size size, List<Offset> offsetList, Color color, {bool isDraw = true, bool isFirst = true}) {
    if (!isDraw) return;
    for (var i = 0; i < offsetList.length; i++) {
      if (isFirst) {
        drawDescription(canvas, offsetList, chartList[i].firstDescription, color, i);
      } else {
        drawDescription(canvas, offsetList, chartList[i].secondDescription, color, i);
      }
    }
  }

  drawDescription(Canvas canvas, List<Offset> offsetList, String description, Color color, int index) {
    ///绘制标题
    TextSpan text = TextSpan(text: description, style: TextStyle(fontSize: 10, color: color));
    _textPainter.text = text;
    _textPainter.layout(); // 进行布局
    Size textSize = _textPainter.size;
    Offset textOffsetPos;
    if (index == 0 && offsetList.length == 1) {
      ///唯一一个点
      textOffsetPos = Offset(offsetList[index].dx, offsetList[index].dy - textSize.height);
    } else if (index == 0 && offsetList.length != 1) {
      ///第一个点
      double a = getAngleByThreeP(a: Offset(0, -maxHeight + 1), b: offsetList[index], c: offsetList[index + 1]) * 180 / pi;
      if (a >= 90) {
        ///钝角
        textOffsetPos = Offset(offsetList[index].dx, offsetList[index].dy - textSize.height * 1.5);
      } else {
        ///锐角
        textOffsetPos = Offset(offsetList[index].dx, offsetList[index].dy + textSize.height / 2);
      }
    } else if (offsetList.length != 1 && index == offsetList.length - 1) {
      ///最后一个点
      double a = getAngleByThreeP(a: offsetList[index - 1], b: offsetList[index], c: Offset(offsetList[index].dx, -maxHeight - 1)) * 180 / pi;
      if (a >= 90) {
        ///钝角
        textOffsetPos = Offset(offsetList[index].dx - textSize.width, offsetList[index].dy - textSize.height * 1.5);
      } else {
        ///锐角
        textOffsetPos = Offset(offsetList[index].dx - textSize.width, offsetList[index].dy + textSize.height / 2);
      }
    } else {
      ///非首尾点
      double a = getAngleByThreeP(a: offsetList[index - 1], b: offsetList[index], c: Offset(offsetList[index].dx, -maxHeight - 1)) * 180 / pi;
      double b = getAngleByThreeP(a: Offset(0, -maxHeight - 1), b: offsetList[index], c: offsetList[index + 1]) * 180 / pi;
      if (a + b >= 180) {
        textOffsetPos = Offset(offsetList[index].dx - textSize.width / 2, offsetList[index].dy - textSize.height * 1.5);
      } else {
        textOffsetPos = Offset(offsetList[index].dx - textSize.width / 2, offsetList[index].dy + textSize.height / 3);
      }
    }
    _textPainter.paint(canvas, textOffsetPos);
  }

  ///求出来的结果是弧度值（另：角度值=弧度*180/π）
  static double getAngleByThreeP({@required Offset a, @required Offset b, @required Offset c}) {
    double a_b_x = a.dx - b.dx;
    double a_b_y = a.dy - b.dy;
    double c_b_x = c.dx - b.dx;
    double c_b_y = c.dy - b.dy;
    double ab_mul_cb = a_b_x * c_b_x + a_b_y * c_b_y;
    double dist_ab = sqrt(a_b_x * a_b_x + a_b_y * a_b_y);
    double dist_cd = sqrt(c_b_x * c_b_x + c_b_y * c_b_y);
    double cosValue = ab_mul_cb / (dist_ab * dist_cd);
    return acos(cosValue);
  }

  drawDots({@required Canvas canvas, @required List<Offset> line, @required Color drawColor}) {
    for (int i = 0; i < chartList.length; i++) {
      if (dotIsSolid) {
        canvas.drawCircle(line[i], 3, Paint()..color = drawColor);
      } else {
        canvas.drawCircle(line[i], 3, Paint()..color = drawColor);
        canvas.drawCircle(line[i], 2, Paint()..color = Colors.white);
      }
    }
  }

  drawLineChart({@required Canvas canvas, @required List<Offset> line, @required Color lineColor}) {
    Offset p1 = line[0];
    Path path = Path()..moveTo(p1.dx, p1.dy);
    for (var i = 1; i < line.length; i++) {
      if (line[i].dy != -1) {
        path.lineTo(line[i].dx, line[i].dy);
      }
    }
    linePaint..strokeWidth = 1;
    linePaint..color = lineColor;
    PathMetrics pms = path.computeMetrics();
    pms.forEach((pm) {
      canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), linePaint..strokeWidth = 2);
    });
  }

  locationOfCollectionPoint(Canvas canvas, Size size) {
    firstPolyLineOffset.clear();
    secondPolylineOffset.clear();
    for (int i = 0; i < chartList.length; i++) {
      firstPolyLineOffset.add(_generatePointsOffset(lineValue: chartList[i].firstPoint, index: i));
      secondPolylineOffset.add(_generatePointsOffset(lineValue: chartList[i].secondPoint, index: i));
    }
  }

  Offset _generatePointsOffset({@required double lineValue, @required int index}) {
    Offset returnOffset;
    if (lineValue != null) {
      double dataHeigh = -(lineValue * maxHeight);
      returnOffset = Offset(xStep * index, dataHeigh);
    } else {
      returnOffset = Offset(xStep * index, -1);
    }
    return returnOffset;
  }

  drawXAxisScaleAndText(Canvas canvas, Size size) {
    canvas.save();

    ///x轴线
    canvas.drawLine(Offset.zero, Offset(maxWidth, 0), axisPaint..color = xAxisColor);

    ///x轴刻度线
    for (int i = 0; i < chartList.length; i++) {
      canvas.drawLine(Offset.zero, Offset(0, 4), axisPaint..color = xAxisColor);

      ///x轴线描述
      _drawXAxisText(canvas, title: chartList[i].name, offset: Offset.zero);
      canvas.translate(xStep, 0);
    }

    canvas.restore();
  }

  drawYAxisScaleAndText(Canvas canvas, Size size) {
    canvas.save();

    ///Y轴线
    canvas.drawLine(Offset.zero, Offset(0, -maxHeight), axisPaint..color = yAxisColor);
    for (int i = 0; i <= 10; i++) {
      canvas.drawLine(Offset.zero, Offset(-4, 0), axisPaint..color = xAxisColor);
      _drawYAxisText(canvas, title: (yAxisMax / 10 * i).toInt().toString(), offset: Offset.zero);
      canvas.translate(0, -yStep);
    }
    canvas.restore();
  }

  ///绘制Y轴文字
  void _drawYAxisText(
    Canvas canvas, {
    String title,
    Offset offset = Offset.zero,
    double fontSize = 6,
    Color color = Colors.black,
  }) {
    ///绘制标题
    TextSpan text = TextSpan(text: title, style: TextStyle(fontSize: fontSize, color: color));
    _textPainter.text = text;
    _textPainter.layout(); // 进行布局
    Size textSize = _textPainter.size;
    Offset textOffsetPos = Offset(offset.dx - textSize.width - 4, offset.dy - textSize.height / 2);
    _textPainter.paint(canvas, textOffsetPos);
  }

  ///绘制X轴文字
  void _drawXAxisText(
    Canvas canvas, {
    String title,
    Offset offset = Offset.zero,
    double fontSize = 6,
    Color color = Colors.black,
  }) {
    ///绘制标题
    TextSpan text = TextSpan(text: title, style: TextStyle(fontSize: fontSize, color: color));
    _textPainter.text = text;
    _textPainter.layout(); // 进行布局
    Size textSize = _textPainter.size;
    Offset textOffsetPos = Offset(offset.dx - textSize.width / 2, offset.dy + textSize.height / 3);
    _textPainter.paint(canvas, textOffsetPos);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
